#pragma once
#include "mutex.hpp"
#include "cond.hpp"
#include <queue>

/* 基于cond.hpp mutex.hpp */
#define defaultcap 5

namespace BlockQueueModule
{
    template <typename T>
    class BlockQueue
    {
        private:
        BlockQueue(const BlockQueue&) = delete;
        const BlockQueue &operator=(const BlockQueue&) = delete;
        bool IsFull() { return _q.size() >= _cap; }
        bool IsEmpty() { return _q.empty(); }
    public:
        BlockQueue()
            : _cap(defaultcap), _p_size(0), _c_size(0)
        {
        }

        void Enqueue(const T& data)
        {
            /* 加锁 */
            _lock.Lock();
            while(IsFull()) /* 如果队列为满，生产者需要等待 */
            {
                _p_size++;
                std::cout << "生产者，进入休眠了: _p_size: " <<  _p_size << std::endl;
                _p_cond.Wait(_lock.GetMutex());
                _p_size--;
            }
            /* 阻塞队列不满，可以入数据 */
            _q.push(data);
            if(_c_size > 0)
            {
                /* 如果存在消费者等待唤醒执行任务 */
                std::cout << "唤醒消费者..." << std::endl;
                _c_cond.Signal();
            }
            _lock.Unlock();
        }

        void Pop(T* out)
        {
            /* 加锁 */
            _lock.Lock();
            while(IsEmpty()) /* 如果队列为空，消费者需要等待 */
            {
                _c_size++;
                std::cout << "消费者，进入休眠了: _c_size: " <<  _c_size << std::endl;
                _c_cond.Wait(_lock.GetMutex());
                _c_size--;
            }

            *out = _q.front();
            _q.pop();

            if(_p_size > 0)
            {
                /* 如果存在生产者等待唤醒执行任务 */
                std::cout << "唤醒生产者者..." << std::endl;
                _p_cond.Signal();
            }

            _lock.Unlock();
        }

        ~BlockQueue()
        {
        }

    private:
        MutexModule::Mutex _lock; /* 锁 */
        /* 两个条件变量 */
        CondModule::Cond _p_cond; /* 生产者变量 */
        CondModule::Cond _c_cond; /* 消费者者变量 */
        /* 阻塞队列 */
        std::queue<T> _q;
        int _cap; /* 阻塞队列最大容量 */
        /* 记录变量 */
        int _p_size; /* 记录生产者等待变量 */
        int _c_size; /* 记录消费者等待变量 */
    };

}